home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
util
/
gnu
/
oleo_src.lha
/
src
/
decompile.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-08-14
|
16KB
|
753 lines
/* Copyright (C) 1990 Free Software Foundation, Inc.
This file is part of Oleo, the GNU Spreadsheet.
Oleo is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
Oleo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Oleo; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
#include "funcdef.h"
#include "sysdef.h"
#include "global.h"
#include "eval.h"
#include "cell.h"
struct pr_node {
int tightness;
int len;
char string[1];
};
char *backslash_a_string EXT2(char *, int);
static VOIDSTAR save_decomp;
static CELLREF decomp_row;
static CELLREF decomp_col;
/* These #defines are so that we don't have to duplicate code below */
#ifdef A0_REFS
#define F0 "@%s()"
#define F1 "@%s(%s)"
#define F2 "@%s(%s,%s)"
#define F3 "@%s(%s,%s,%s)"
#define F4 "@%s(%s,%s,%s,%s)"
#define FN1 "@%s(%s"
#else
#define F0 "%s()"
#define F1 "%s(%s)"
#define F2 "%s(%s,%s)"
#define F3 "%s(%s,%s,%s)"
#define F4 "%s(%s,%s,%s,%s)"
#define FN1 "%s(%s"
#endif
/* We decompile things with these wierd node-things. It's ugly, but it works.
*/
static struct pr_node *
n_alloc FUN3N(int, size, int, tightness, char *, fmt)
{
struct pr_node *ret;
va_list args;
ret=ck_malloc(sizeof(struct pr_node)+size+1);
ret->len=size;
ret->tightness=tightness;
var_start(args,fmt);
vsprintf(ret->string,fmt,args);
va_end(args);
return ret;
}
#define n_free(x) free(x)
static struct pr_node *
byte_decompile FUN1(unsigned char *, expr)
{
unsigned char byte;
double tmp_flt;
long tmp_lng;
char *tmp_str;
struct var *v;
unsigned long_skp;
unsigned char save_val;
unsigned jumpto;
struct pr_node *new = 0;
int pri;
int aso;
char *chr;
static struct pr_node **the_line;
static int line_alloc;
static struct pr_node **c_node;
struct function *f;
if(!the_line) {
the_line=(struct pr_node **)ck_malloc(20*sizeof(struct pr_node *));
line_alloc=20;
c_node=the_line;
}
#ifdef TEST
if(!expr)
panic("No expression to decompile");
#endif
next_byte:
byte= *expr++;
if(byte<USR1)
f= &the_funs[byte];
else if(byte<SKIP) {
tmp_lng= *expr++;
f= &usr_funs[byte-USR1][tmp_lng];
} else
f= &skip_funs[byte-SKIP];
if(f->fn_argn&X_J)
jumpto= *expr++;
else if(f->fn_argn&X_JL) {
jumpto=expr[0]+((unsigned)(expr[1])<<8);
expr+=2;
}
#ifdef TEST
else
jumpto=0;
#endif
switch(GET_COMP(f->fn_comptype)) {
case C_IF:
if(expr[jumpto-2]!=SKIP) {
long_skp=1;
save_val=expr[jumpto-3];
expr[jumpto-3]=0;
} else {
long_skp=0;
save_val=expr[jumpto-2];
expr[jumpto-2]=0;
}
c_node[0]=byte_decompile(expr);
c_node++;
if(long_skp) {
expr[jumpto-3]=save_val;
expr+=jumpto;
jumpto=expr[-2]+((unsigned)(expr[-1])<<8);
} else {
expr[jumpto-2]=save_val;
expr+=jumpto;
jumpto=expr[-1];
}
save_val=expr[jumpto];
expr[jumpto]=0;
c_node[0]=byte_decompile(expr);
c_node-=2;
expr[jumpto]=save_val;
expr+=jumpto;
if(byte==IF || byte==IF_L) {
if(c_node[0]->tightness<=1)
new=n_alloc(8+c_node[0]->len+c_node[1]->len+c_node[2]->len,
1,
"(%s) ? %s : %s",c_node[0]->string,c_node[1]->string,c_node[2]->string);
else
new=n_alloc(6+c_node[0]->len+c_node[1]->len+c_node[2]->len,
1,
"%s ? %s : %s",c_node[0]->string,c_node[1]->string,c_node[2]->string);
} else
new=n_alloc(6+c_node[0]->len+c_node[1]->len+c_node[2]->len+strlen(f->fn_str),
1000,
F3,f->fn_str,c_node[0]->string,c_node[1]->string,c_node[2]->string);
n_free(c_node[0]);
n_free(c_node[1]);
n_free(c_node[2]);
break;
case C_ANDOR:
save_val=expr[jumpto];
expr[jumpto]=0;
c_node[0]=byte_decompile(expr);
expr[jumpto]=save_val;
expr+=jumpto;
c_node++;
if(ISINFIX(f->fn_comptype)) {
pri= GET_IN(f->fn_comptype);
aso= GET_ASO(f->fn_comptype);
chr= f->fn_str;
goto do_infix;
} else
goto do_fn2;
case C_STR:
tmp_str=backslash_a_string((char *)expr+jumpto,1);
new=n_alloc(strlen(tmp_str)+1,
1000,
tmp_str);
break;
case C_CELL:
{
#ifndef A0_REFS
int num1,num2;
char *str;
#endif
CELLREF row,col;
row=GET_ROW(expr);
col=GET_COL(expr);
expr+=EXP_ADD;
#ifdef A0_REFS
new=n_alloc(30,1000,f->fn_str,col_to_str(col),row);
#else
if(byte&ROWREL) {
num1=row-decomp_row;
if(byte&COLREL) {
num2=col-decomp_col;
if(row==decomp_row && col==decomp_col)
str="rc";
else if(row==decomp_row) {
str="rc[%+d]";
num1=num2;
} else if(col==decomp_col)
str="r[%+d]c";
else
str=f->fn_str;
} else if(row==decomp_row) {
str="rc%u";
num1=num2=col;
} else {
str=f->fn_str;
num2=col;
}
} else if(byte&COLREL) {
num1=row;
num2=col-decomp_col;
if(col==decomp_col)
str="r%uc";
else
str=f->fn_str;
} else {
str=f->fn_str;
num1=row;
num2=col;
}
new=n_alloc(30,1000,str,num1,num2);
#endif
new->len=strlen(new->string);
}
break;
case C_RANGE:
{
#ifndef A0_REFS
char tmprbuf[40];
char tmpcbuf[40];
#endif
struct rng rng;
GET_RNG(expr,&rng);
expr+=EXP_ADD_RNG;
#ifdef A0_REFS
new=n_alloc(40,1000,f->fn_str,col_to_str(rng.lc),rng.lr,col_to_str(rng.hc),rng.hr);
#else
/* Check for special cases */
if(rng.lr==rng.hr && ((byte&LRREL)?1:0)==((byte&HRREL)?1:0)) {
if(byte&LRREL) {
if(rng.lr==decomp_row) {
tmprbuf[0]='r';
tmprbuf[1]='\0';
} else
(void)sprintf(tmprbuf,"r[%+d]",rng.lr-decomp_row);
} else
sprintf(tmprbuf,"r%u",rng.lr);
} else if((byte&LRREL) && (byte&HRREL)) {
int r1,r2,rtmp;
r1=rng.lr-decomp_row;
r2=rng.hr-decomp_row;
if(r1<r2)
rtmp=r1,r1=r2,r2=rtmp;
(void)sprintf(tmprbuf,"r[%+d:%+d]",r1,r2);
} else if((byte&LRREL))
(void)sprintf(tmprbuf,"r[%+d]:%u",rng.lr-decomp_row,rng.hr);
else if(byte&HRREL)
(void)sprintf(tmprbuf,"r%u:[%+d]",rng.lr,rng.hr-decomp_row);
else if(rng.lr<rng.hr)
(void)sprintf(tmprbuf,"r%u:%u",rng.lr,rng.hr);
else
(void)sprintf(tmprbuf,"r%u:%u",rng.hr,rng.lr);
if(rng.lc==rng.hc && ((byte&LCREL)?1:0)==((byte&HCREL)?1:0)) {
if(byte&LCREL) {
if(rng.lc==decomp_col) {
tmpcbuf[0]='c';
tmpcbuf[1]='\0';
} else
sprintf(tmpcbuf,"c[%+d]",rng.lc-decomp_col);
} else
sprintf(tmpcbuf,"c%u",rng.lc);
} else if((byte&LCREL) && (byte&HCREL)) {
int c1,c2,ctmp;
c1=rng.lc-decomp_col;
c2=rng.hc-decomp_col;
if(c1<c2)
ctmp=c1,c1=c2,c2=ctmp;
(void)sprintf(tmpcbuf,"c[%+d:%+d]",c1,c2);
} else if((byte&LCREL))
(void)sprintf(tmpcbuf,"c[%+d]:%u",rng.lc-decomp_col,rng.hc);
else if(byte&HCREL)
(void)sprintf(tmpcbuf,"c%u:[%+d]",rng.lc,rng.hc-decomp_col);
else if(rng.lc<rng.hc)
(void)sprintf(tmpcbuf,"c%u:%u",rng.lc,rng.hc);
else
(void)sprintf(tmpcbuf,"c%u:%u",rng.hc,rng.lc);
new=n_alloc(40,1000,"%s%s",tmprbuf,tmpcbuf);
#endif
new->len=strlen(new->string);
}
break;
case C_CONST:
new=n_alloc(strlen(f->fn_str)+1,1000,f->fn_str);
break;
case C_FN0:
case C_FN0X:
case C_FN0|C_T:
new=n_alloc(strlen(f->fn_str)+3,
1000,
F0,
f->fn_str);
break;
case C_FN1:
--c_node;
new=n_alloc(c_node[0]->len+strlen(f->fn_str)+3,
1000,
F1, f->fn_str, c_node[0]->string);
n_free(*c_node);
break;
case C_UNA:
--c_node;
if(c_node[0]->tightness<9) {
new=n_alloc(3+c_node[0]->len,
9,
"%s(%s)",f->fn_str,c_node[0]->string);
} else {
new=n_alloc(1+c_node[0]->len,
9,
"%s%s",f->fn_str,c_node[0]->string);
}
n_free(*c_node);
break;
case C_INF:
pri=GET_IN(f->fn_comptype);
aso=GET_ASO(f->fn_comptype);
chr=f->fn_str;
do_infix:
c_node-=2;
if(c_node[0]->tightness<pri || (c_node[0]->tightness==pri && aso!=1)) {
if(c_node[1]->tightness<pri || (c_node[1]->tightness==pri && aso!=-1))
new=n_alloc(7+c_node[0]->len+c_node[1]->len,
pri,
"(%s) %s (%s)",c_node[0]->string,chr,c_node[1]->string);
else
new=n_alloc(5+c_node[0]->len+c_node[1]->len,
pri,
"(%s) %s %s",c_node[0]->string,chr,c_node[1]->string);
} else if(c_node[1]->tightness<pri || (c_node[1]->tightness==pri && aso!=-1))
new=n_alloc(5+c_node[0]->len+c_node[1]->len,
pri,
"%s %s (%s)",c_node[0]->string,chr,c_node[1]->string);
else
new=n_alloc(3+c_node[0]->len+c_node[1]->len,
pri,
"%s %s %s",c_node[0]->string,chr,c_node[1]->string);
n_free(c_node[0]);
n_free(c_node[1]);
break;
case C_FN2:
do_fn2:
c_node-=2;
new=n_alloc(c_node[0]->len+c_node[1]->len+strlen(f->fn_str)+5,
1000,
F2,f->fn_str,c_node[0]->string,c_node[1]->string);
n_free(c_node[0]);
n_free(c_node[1]);
break;
case C_FN3:
c_node-=3;
new=n_alloc(c_node[0]->len+c_node[1]->len+c_node[2]->len+strlen(f->fn_str)+7,
1000,
F3,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string);
n_free(c_node[0]);
n_free(c_node[1]);
n_free(c_node[2]);
break;
case C_FNN:
aso= *expr++;
c_node-=aso;
if(aso==1)
new=n_alloc(3+c_node[0]->len+strlen(f->fn_str),
1000,
F1,f->fn_str,c_node[0]->string);
else {
new=n_alloc(2+c_node[0]->len+strlen(f->fn_str),
1000,
FN1,f->fn_str,c_node[0]->string);
--aso;
for(pri=1;pri<aso;pri++) {
n_free(c_node[0]);
c_node[0]=new;
new=n_alloc(2+new->len+c_node[pri]->len,
1000,
"%s, %s",new->string,c_node[pri]->string);
}
n_free(c_node[0]);
c_node[0]=new;
new=n_alloc(3+new->len+c_node[aso]->len,
1000,
"%s, %s)",new->string,c_node[aso]->string);
}
n_free(c_node[0]);
break;
case C_FN4:
c_node-=4;
new=n_alloc(c_node[0]->len+c_node[1]->len+c_node[2]->len+c_node[3]->len+strlen(f->fn_str)+6,
1000,
F4,
f->fn_str,
c_node[0]->string,
c_node[1]->string,
c_node[2]->string,
c_node[3]->string);
n_free(c_node[0]);
n_free(c_node[1]);
n_free(c_node[2]);
n_free(c_node[3]);
break;
case C_ERR:
tmp_str=(char *)expr+jumpto;
expr++;
new=n_alloc(strlen(tmp_str)+1,1000,tmp_str);
/* bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_str,sizeof(char *));
expr+=sizeof(char *);
new=n_alloc(strlen(tmp_str)+1,1000,f->fn_str,tmp_str); */
break;
case C_FLT:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_flt,sizeof(double));
expr+=sizeof(double);
new=n_alloc(20,1000,f->fn_str,tmp_flt);
new->len=strlen(new->string);
break;
case C_INT:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_lng,sizeof(long));
expr+=sizeof(long);
new=n_alloc(20,1000,f->fn_str,tmp_lng);
new->len=strlen(new->string);
break;
case C_VAR:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&v,sizeof(struct var *));
expr+=sizeof(struct var *);
new=n_alloc(strlen(v->var_name)+1,
1000,
f->fn_str, v->var_name);
break;
default:
panic("Bad decompile %d",f->fn_comptype);
}
*c_node++=new;
if(c_node== &the_line[line_alloc]) {
line_alloc*=2;
the_line=ck_realloc(the_line,line_alloc*sizeof(struct pr_node *));
c_node= &the_line[line_alloc/2];
}
if(*expr)
goto next_byte;
/* if(c_node != &the_line[1]) {
error_msg("%d values on decompile stack!",c_node - the_line);
return the_line[0];
} */
new= *--c_node;
/* free(the_line); */
return new;
}
/* Actual entry points to this file */
/* decomp(row, col, cell) returns a string that can be byte_compiled to create
cell->formula decomp_free() frees up the allocated string */
char *
decomp FUN3(CELLREF, r, CELLREF, c, CELL *, cell)
{
struct pr_node *ret;
char *str;
extern char *bname[];
extern char *strdup EXT1(const char *);
extern char *flt_to_str EXT1(double);
decomp_row=r;
decomp_col=c;
if(cell->cell_formula==0) {
switch(GET_TYP(cell)) {
case 0:
str=ck_malloc(1);
str[0]='\0';
break;
case TYP_FLT:
str=strdup(flt_to_str(cell->cell_flt));
break;
case TYP_INT:
str=ck_malloc(20);
sprintf(str,"%ld",cell->cell_int);
break;
case TYP_STR:
str=strdup(backslash_a_string(cell->cell_str,1));
break;
case TYP_BOL:
str=strdup(bname[cell->cell_bol]);
break;
case TYP_ERR:
str=strdup(ename[cell->cell_bol]);
break;
#ifdef TEST
default:
str=0;
panic("Unknown type %d in decomp",GET_TYP(cell));
#endif
}
save_decomp=(VOIDSTAR)str;
return str;
} else
ret=byte_decompile(cell->cell_formula);
save_decomp=(VOIDSTAR)ret;
return &(ret->string[0]);
}
void
decomp_free FUN0()
{
#ifdef TEST
if(!save_decomp)
panic("No save decomp");
n_free(save_decomp);
save_decomp= (VOIDSTAR)0;
#else
n_free(save_decomp);
#endif
}
/* This takes a string and returns a backslashed form suitable for printing.
Iff add_quote is true, it'll add "s at the beginning and end.
Note that this returns a pointer to a static area that is overwritten with
each call. . .
*/
char *
backslash_a_string FUN2(char *,string, int,add_quote)
{
char *pf;
char *pt;
int ch;
int size;
int len;
static char *cbuf;
static int s_cbuf;
#define ALLOC_PT() \
len=strlen(pf); \
size=pf-string; \
if(s_cbuf<3+size+4*len) { \
s_cbuf=3+size+4*len; \
cbuf= (cbuf) ? ck_realloc(cbuf,s_cbuf) : ck_malloc(s_cbuf); \
} \
if(size) \
bcopy(string,cbuf,size); \
pt=cbuf+size; \
pt=0;
pf=string;
if(add_quote) {
ALLOC_PT()
*pt++='"';
}
for(;*pf;pf++) {
ch= *pf;
if(ch>=' ' && ch<='~' && ch!='\\' && (ch!='"' || !add_quote)) {
if(pt)
*pt++=ch;
continue;
}
if(!pt) {
ALLOC_PT()
}
if(ch=='\\') {
*pt++='\\';
*pt++='\\';
} else if(ch=='"') {
*pt++='\\';
*pt++=ch;
} else {
*pt++='\\';
*pt++=((ch>>6)&0x3)+'0';
*pt++=((ch>>3)&0x7)+'0';
*pt++=( ch &0x7)+'0';
}
}
if(add_quote)
*pt++='"';
if(pt) {
*pt++='\0';
return cbuf;
}
return string;
}
#ifdef TEST
void
dbg_print_formula FUN1(unsigned char *,expr)
{
unsigned char byte;
struct function *f;
double tmp_flt;
char *tmp_str;
long tmp_int;
struct var *v;
struct rng rng;
char *buf;
unsigned jumpto;
extern char print_buf[];
extern char *strcpy();
if(!expr)
return;
strcpy(print_buf,"Formula: ");
buf=print_buf+9;
while(*expr) {
byte= *expr++;
if(byte<USR1)
f= &the_funs[byte];
else if(byte<SKIP) {
tmp_int= *expr++;
f= &usr_funs[byte-USR1][tmp_int];
} else
f= &skip_funs[byte-SKIP];
if(f->fn_argn&X_J)
jumpto= *expr++;
else if(f->fn_argn&X_JL) {
jumpto= expr[0]+((unsigned)(expr[1])<<8);
expr+=2;
} else
jumpto=0;
switch(GET_COMP(f->fn_comptype)) {
case C_IF:
sprintf(buf," if%d.%u",byte,jumpto);
break;
case C_ANDOR:
sprintf(buf," andor%d.%u",byte,jumpto);
break;
case C_ERR:
tmp_str=(char *)(expr+jumpto);
byte= *expr++;
sprintf(buf," err%d.%p(%s)",byte,tmp_str,tmp_str);
break;
case C_FLT:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_flt,sizeof(double));
expr+=sizeof(double);
sprintf(buf," flt.%.15g",tmp_flt);
break;
case C_INT:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&tmp_int,sizeof(long));
expr+=sizeof(long);
sprintf(buf," int.%ld",tmp_int);
break;
case C_STR:
tmp_str=(char *)(expr+jumpto);
sprintf(buf," str.%p.%s",tmp_str,tmp_str);
break;
case C_VAR:
bcopy((VOIDSTAR)expr,(VOIDSTAR)&v,sizeof(struct var *));
expr+=sizeof(struct var *);
sprintf(buf," var.%p.%s",v,v->var_name);
break;
case C_CELL:
sprintf(buf," ref%d.%u.%u",byte,GET_ROW(expr-1),GET_COL(expr-1));
expr+=EXP_ADD;
break;
case C_RANGE:
GET_RNG(expr,&rng);
sprintf(buf," rng%d.%u-%u,%u-%u",byte,rng.lr,rng.hr,rng.lc,rng.hc);
expr+=EXP_ADD_RNG;
break;
case C_FN0:
case C_FN0X:
case C_FN1:
case C_FN2:
case C_FN3:
case C_FN4:
case C_UNA:
case C_INF:
sprintf(buf," fun%d.%s.%p",byte,f->fn_str,f->fn_fun);
break;
case C_FNN:
sprintf(buf," funn%d.%s.%p.%d",byte,f->fn_str,f->fn_fun,*expr++);
break;
case C_CONST:
sprintf(buf," const%s",f->fn_str);
break;
case C_SKIP:
sprintf(buf," skip.%d",jumpto);
break;
case 0:
sprintf(buf," ???%d",byte);
break;
default:
error_msg("Unknown decompile type %d",f->fn_comptype);
}
buf+=strlen(buf);
}
text_line(print_buf);
}
#endif